package com.xuan.xseq.range.impl.db;

import com.xuan.xseq.exception.SequenceException;
import com.xuan.xseq.range.SeqRange;
import com.xuan.xseq.range.AbstractSeqRangeConfig;
import com.xuan.xseq.range.SeqRangeMgr;

/**
 * DB区间管理器
 * Created by xuan on 2018/4/29.
 */
public class DbSeqRangeMgr implements SeqRangeMgr {

    private DbSeqRangeConfig config;

    @Override
    public SeqRange nextRange(String name) throws SequenceException {
        if (isEmpty(name)) {
            throw new SecurityException("[DbSeqRangeMgr-nextRange] name is empty.");
        }

        Long oldValue;
        Long newValue;

        for (int i = 0; i < config.getRetryTimes(); i++) {
            oldValue = DBHelper.selectRange(config.getDataSource(), config.getTableName(), name, config.getStepStart());

            if (null == oldValue) {
                //区间不存在，重试
                continue;
            }

            newValue = oldValue + config.getStep();

            if (DBHelper.updateRange(config.getDataSource(), config.getTableName(), newValue, oldValue, name)) {
                return new SeqRange(oldValue + 1, newValue);
            }
            //else 失败重试
        }

        throw new SequenceException("Retried too many times, retryTimes = " + config.getRetryTimes());
    }

    @Override
    public void setSeqRangeConfig(AbstractSeqRangeConfig seqRangeConfig) {
        checkSeqRangeConfig(seqRangeConfig);
        this.config = (DbSeqRangeConfig) seqRangeConfig;
    }

    @Override
    public void init() {
        DBHelper.createTable(config.getDataSource(), config.getTableName());
    }

    private void checkSeqRangeConfig(AbstractSeqRangeConfig seqRangeConfig) {
        if (null == seqRangeConfig) {
            throw new SecurityException("[DbSeqRangeMgr-checkSeqRangeConfig] seqRangeConfig is null.");
        }

        if (!(seqRangeConfig instanceof DbSeqRangeConfig)) {
            throw new SecurityException(
                    "[DbSeqRangeMgr-checkSeqRangeConfig] seqRangeConfig not instanceof DbSeqRangeConfig.");
        }

        DbSeqRangeConfig dbSeqRangeConfig = (DbSeqRangeConfig) seqRangeConfig;

        if (dbSeqRangeConfig.getStep() <= 0) {
            throw new SecurityException(
                    "[DbSeqRangeMgr-checkSeqRangeConfig] dbSeqRangeConfig.step must greater than 0.");
        }

        if (dbSeqRangeConfig.getRetryTimes() <= 0) {
            throw new SecurityException(
                    "[DbSeqRangeMgr-checkSeqRangeConfig] dbSeqRangeConfig.retryTimes must greater than 0.");
        }

        if (isEmpty(dbSeqRangeConfig.getTableName())) {
            throw new SecurityException("[DbSeqRangeMgr-checkSeqRangeConfig] dbSeqRangeConfig.tableName is empty.");
        }

        if (null == dbSeqRangeConfig.getDataSource()) {
            throw new SecurityException("[DbSeqRangeMgr-checkSeqRangeConfig] dbSeqRangeConfig.dataSource is empty.");
        }
    }

    private boolean isEmpty(String str) {
        return null == str || str.trim().length() == 0;
    }

}
